home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / newtee / RCS / newtee.c,v < prev    next >
Encoding:
Text File  |  1990-10-31  |  10.1 KB  |  479 lines

  1. head     1.4;
  2. branch   ;
  3. access   ;
  4. symbols  ;
  5. locks    ; strict;
  6. comment  @ * @;
  7.  
  8.  
  9. 1.4
  10. date     90.10.31.14.57.55;  author mgbaker;  state Exp;
  11. branches ;
  12. next     1.3;
  13.  
  14. 1.3
  15. date     90.05.07.11.46.04;  author mgbaker;  state Exp;
  16. branches ;
  17. next     1.2;
  18.  
  19. 1.2
  20. date     90.05.07.11.11.04;  author mgbaker;  state Exp;
  21. branches ;
  22. next     1.1;
  23.  
  24. 1.1
  25. date     90.05.04.19.40.34;  author mgbaker;  state Exp;
  26. branches ;
  27. next     ;
  28.  
  29.  
  30. desc
  31. @New tee program for syslogs.
  32. @
  33.  
  34.  
  35. 1.4
  36. log
  37. @Fixed non-blocking I/O problem.
  38. @
  39. text
  40. @/* 
  41.  * newtee.c --
  42.  *
  43.  *    Program to take standard input or input from a named file and
  44.  *     transcribe it to both the standard output and the given files.
  45.  *    It is unbuffered.  The writer process is the child of the reader
  46.  *    process.  If the child blocks writing to the files due to a file
  47.  *    server being down, we still want the output on stdout, so the
  48.  *    parent reader process is set up not to block and has the
  49.  *    responsibility to send the data to stdout.
  50.  *
  51.  * Copyright 1990 Regents of the University of California
  52.  * Permission to use, copy, modify, and distribute this
  53.  * software and its documentation for any purpose and without
  54.  * fee is hereby granted, provided that the above copyright
  55.  * notice appear in all copies.  The University of California
  56.  * makes no representations about the suitability of this
  57.  * software for any purpose.  It is provided "as is" without
  58.  * express or implied warranty.
  59.  */
  60.  
  61. #ifndef lint
  62. static char rcsid[] = "$Header: /sprite/src/cmds/newtee/RCS/newtee.c,v 1.3 90/05/07 11:46:04 mgbaker Exp Locker: mgbaker $ SPRITE (Berkeley)";
  63. #endif /* not lint */
  64.  
  65. #include <sprite.h>
  66. #include <stdio.h>
  67. #include <option.h>
  68. #include <signal.h>
  69. #include <sys/file.h>
  70. #include <sys/types.h>
  71. #include <fcntl.h>
  72. #include <errno.h>
  73.  
  74.  
  75. char    in[BUFSIZ];    /* Input data from read process put here. */
  76. char     out[BUFSIZ];    /* Output data for write process put here. */
  77. int    pipedesc[2];    /* Pipe to pass data from read process to write proc. */
  78. int    inFd;        /* File descr. for input to program. */
  79. int    outFiles[20];    /* Files to put output data in. */
  80. int    maxFileIndex = -1;    /* The index of the last output file. */
  81. int    childPID;    /* Pid of write process. */
  82.  
  83. /*
  84.  * Options to program.
  85.  */
  86. Boolean    append = FALSE;    /* Append to output files rather than overwrite them. */
  87. Boolean    keepGoing = FALSE;    /* Always wait for more input (tail -f). */
  88. char    *inputFile = NULL;    /* Get input from file instead of stdin. */
  89.  
  90. Option optionArray[] = {
  91.     {OPT_TRUE, "append", (char *)&append,
  92.     "Append to files rather than overwrite them."},
  93.     {OPT_STRING, "inputFile", (char *)&inputFile,
  94.     "Use this file as input rather than standard input."},
  95.     {OPT_TRUE, "keepGoing", (char *)&keepGoing,
  96.     "Keep trying to read data from input even if the end is reached."},
  97.  
  98. };
  99. int numOptions = sizeof(optionArray) / sizeof(Option);
  100.  
  101. /*
  102.  * Forward declarations.
  103.  */
  104. extern    void    KillChild();
  105. extern    int    CleanupFunc();
  106. extern    void    InputReader();
  107. extern    void    OutputWriter();
  108.  
  109.  
  110. /*
  111.  *----------------------------------------------------------------------
  112.  *
  113.  * main --
  114.  *
  115.  *    Gather arguments and setup reading and writing processes.
  116.  *
  117.  * Results:
  118.  *    None.
  119.  *
  120.  * Side effects:
  121.  *    None.
  122.  *
  123.  *----------------------------------------------------------------------
  124.  */
  125. void
  126. main(argc, argv)
  127.     int argc;
  128.     char *argv[];
  129. {
  130.     int        modeFlags;
  131.  
  132.     argc = Opt_Parse(argc, argv, optionArray, numOptions, 0);
  133.     if (append) {
  134.     modeFlags = O_RDWR | O_APPEND | O_CREAT;
  135.     } else {
  136.     modeFlags = O_RDWR | O_CREAT | O_TRUNC;
  137.     }
  138.     if (argc <= 1) {
  139.     fprintf(stderr, "You must give at least one filename for output.\n");
  140.     exit(1);
  141.     }
  142.  
  143.     /*
  144.      * Gather output files and try to open them all.  Keep their descriptors.
  145.      */
  146.     for ( ; argc > 1; argc--) {
  147.     if (maxFileIndex + 1 == sizeof (outFiles) / sizeof (outFiles[0])) {
  148.         fprintf(stderr, "Can only handle %d output files.\n",
  149.         maxFileIndex + 1);
  150.         exit(1);
  151.     }
  152.     outFiles[maxFileIndex + 1] = open(argv[argc - 1], modeFlags, 0666);
  153.     if (outFiles[maxFileIndex + 1] < 0) {
  154.         fprintf(stderr, "Couldn't open output file %s\n",
  155.             argv[argc - 1]);
  156.     } else {
  157.         maxFileIndex++;
  158.     }
  159.     }
  160.     if (maxFileIndex < 0) {
  161.     perror("Couldn't open any output files");
  162.     exit(1);
  163.     }
  164.     
  165.     /*
  166.      * Now check whether we must open an input file.
  167.      */
  168.     if (inputFile != NULL) {
  169.     inFd = open(inputFile, O_RDONLY, 0);
  170.     if (inFd < 0) {
  171.         perror("Couldn't open input file");
  172.         exit(1);
  173.     }
  174.     } else {
  175.     inFd = 0;        /* Use standard input by default. */
  176.     }
  177.  
  178.     /*
  179.      * Set up the pipe between reader and writer.
  180.      */
  181.     if (pipe(pipedesc) != 0) {
  182.     perror("Couldn't create pipe.");
  183.     exit(1);
  184.     }
  185.  
  186.     /*
  187.      * Don't allow reader process to block since we want it to keep on
  188.      * sending its output to stdout even if a file server is down which
  189.      * could block the writer process.
  190.      */  
  191.     if (fcntl(pipedesc[1], F_SETFL, FNDELAY) == -1) {
  192.     perror("Coulnd't set pipe to non-blocking");
  193.     exit(1);
  194.     }
  195.  
  196.     /*
  197.      * Fork writer process.
  198.      */
  199.     switch (childPID = fork()) {
  200.     case 0: /* child */
  201.     OutputWriter();
  202.     break;
  203.     case -1: /* error */
  204.     perror("Couldn't fork child process");
  205.     exit(1);
  206.     default: /* parent */
  207.     (void) signal(SIGCHLD, CleanupFunc);
  208.     InputReader();
  209.     break;
  210.     }
  211.  
  212.     KillChild();
  213.     exit(0);
  214. }
  215.  
  216.  
  217.  
  218.  
  219. /*
  220.  *----------------------------------------------------------------------
  221.  *
  222.  * InputReader --
  223.  *
  224.  *    Parent process that reads from input to program and copies the
  225.  *    data through a pipe to the child reader process.  This parent is
  226.  *    set up not to block on the child and has the responsibility to
  227.  *    copy its input to stdout so that we see it even if the child
  228.  *    writer process blocks due to server failure.
  229.  *
  230.  * Results:
  231.  *    It never returns.
  232.  *
  233.  * Side effects:
  234.  *    Data read and copied.
  235.  *
  236.  *----------------------------------------------------------------------
  237.  */
  238. void
  239. InputReader()
  240. {
  241.     int        readCount;    /* Count of data read into program. */
  242.     int        writeCount;    /* Count of data written to pipe, etc. */
  243.  
  244.  
  245.     (void) close(pipedesc[0]);
  246.  
  247.     for ( ; ; ) {
  248.     /*
  249.      * Read data into program.
  250.      */
  251.     readCount = read(inFd, &in, sizeof (in));
  252.     if (readCount < 0) {
  253.         perror("Couldn't read input");
  254.         KillChild();
  255.         exit(1);
  256.     }
  257.     /*
  258.      * Don't accept end-of-file if we're in "tail -f" mode.
  259.      */
  260.     if (readCount == 0 && keepGoing) {
  261.         continue;
  262.     } else if (readCount == 0) {    /* end of file */
  263.         KillChild();
  264.         exit(0);
  265.     }
  266.  
  267.     /*
  268.      * Copy input to stdout.
  269.      */
  270.     writeCount = write(2, &in, readCount);
  271.     if (writeCount < 0) {
  272.         perror("Couln't write to stdout");
  273.         KillChild();
  274.         exit(1);
  275.     }
  276.     if (writeCount < readCount) {
  277.         perror("Couldn't complete write to stdout");
  278.         KillChild();
  279.         exit(1);
  280.     }
  281.  
  282.     /*
  283.      * Now copy the input to the non-blocking pipe.
  284.      */
  285.     writeCount = write(pipedesc[1], &in, readCount);
  286.     if (writeCount < 0 && errno != EWOULDBLOCK) {
  287.         perror("Couln't write to pipe");
  288.         KillChild();
  289.         exit(1);
  290.     }
  291.     if (writeCount < readCount) {
  292.         perror("Couldn't complete write to pipe");
  293.         KillChild();
  294.         exit(1);
  295.     }
  296.     }
  297.     KillChild();
  298.     exit(0);
  299. }
  300.  
  301.  
  302. /*
  303.  *----------------------------------------------------------------------
  304.  *
  305.  * OutputWriter --
  306.  *
  307.  *    Child process that reads from pipe and copies the
  308.  *    data to the output files.
  309.  *
  310.  * Results:
  311.  *    It never returns.
  312.  *
  313.  * Side effects:
  314.  *    Data read and copied.
  315.  *
  316.  *----------------------------------------------------------------------
  317.  */
  318. void
  319. OutputWriter()
  320. {
  321.     int        readCount;    /* Count of bytes read from pipe. */
  322.     int        writeCount;    /* Count of bytes written to files. */
  323.     int        theFile;    /* The current output file descriptor. */
  324.  
  325.     (void) close(pipedesc[1]);
  326.  
  327.     for ( ; ; ) {
  328.     /*
  329.      * Read data from parent process.
  330.      */
  331.     readCount = read(pipedesc[0], &out, sizeof (out));
  332.     if (readCount < 0) {
  333.         perror("Couldn't read from pipe");
  334.         _exit(1);
  335.     }
  336.     if (readCount == 0) {
  337.         exit(0);
  338.     }
  339.  
  340.     /*
  341.      * Write the data to each output file.
  342.      */
  343.     for (theFile = 0; theFile <= maxFileIndex; theFile++) {
  344.         writeCount = write(outFiles[theFile], &out, readCount);
  345.         if (writeCount < 0) {
  346.         perror("Couldn't write output to file");
  347.         _exit(1);
  348.         }
  349.         if (writeCount < readCount) {
  350.         perror("Couldn't write all of output");
  351.         _exit(1);
  352.         }
  353.     }
  354.     }
  355.     _exit(0);
  356. }
  357.  
  358.  
  359.  
  360. /*
  361.  *----------------------------------------------------------------------
  362.  *
  363.  * CleanupFunc --
  364.  *
  365.  *    Called from signal handler by parent if it's child dies.
  366.  *    If the child dies, the parent should too.  At least, that's the
  367.  *    current idea.
  368.  *
  369.  * Results:
  370.  *    None.
  371.  *
  372.  * Side effects:
  373.  *    Death.
  374.  *
  375.  *----------------------------------------------------------------------
  376.  */
  377. int
  378. CleanupFunc()
  379. {
  380.     exit(1);
  381. }
  382.  
  383.  
  384. /*
  385.  *----------------------------------------------------------------------
  386.  *
  387.  * KillChild --
  388.  *
  389.  *    Called by the parent process if it's going to die.  We want the
  390.  *    child to die too in that case.
  391.  *
  392.  * Results:
  393.  *    None.
  394.  *
  395.  * Side effects:
  396.  *    Death.
  397.  *
  398.  *----------------------------------------------------------------------
  399.  */
  400. void
  401. KillChild()
  402. {
  403.     (void) kill(childPID, SIGKILL);
  404.     return;
  405. }
  406. @
  407.  
  408.  
  409. 1.3
  410. log
  411. @fixed it again.
  412. @
  413. text
  414. @d23 1
  415. a23 1
  416. static char rcsid[] = "$Header: /sprite/src/cmds/newtee/RCS/newtee.c,v 1.2 90/05/07 11:11:04 mgbaker Exp Locker: mgbaker $ SPRITE (Berkeley)";
  417. d152 1
  418. a152 1
  419.     if (fcntl(pipedesc[1], FNDELAY, 0) == -1) {
  420. @
  421.  
  422.  
  423. 1.2
  424. log
  425. @Added fix to signal stuff.
  426. @
  427. text
  428. @d23 1
  429. a23 1
  430. static char rcsid[] = "$Header: /sprite/src/cmds/newtee/RCS/newtee.c,v 1.1 90/05/04 19:40:34 mgbaker Exp Locker: mgbaker $ SPRITE (Berkeley)";
  431. a65 1
  432. extern    int    KillBoth();
  433. a168 3
  434.     (void) signal(SIGHUP, KillBoth);
  435.     (void) signal(SIGINT, KillBoth);
  436.     (void) signal(SIGQUIT, KillBoth);
  437. d206 2
  438. d286 2
  439. a365 24
  440. }
  441.  
  442.  
  443. /*
  444.  *----------------------------------------------------------------------
  445.  *
  446.  * KillBoth --
  447.  *
  448.  *    Called by the parent process if it gets a death signal.  We want the
  449.  *    child to die and the parent.
  450.  *
  451.  * Results:
  452.  *    None.
  453.  *
  454.  * Side effects:
  455.  *    Death.
  456.  *
  457.  *----------------------------------------------------------------------
  458.  */
  459. int
  460. KillBoth()
  461. {
  462.     (void) kill(childPID, SIGKILL);
  463.     exit(0);
  464. @
  465.  
  466.  
  467. 1.1
  468. log
  469. @Initial revision
  470. @
  471. text
  472. @d23 1
  473. a23 1
  474. static char rcsid[] = "$Header: /sprite/lib/forms/RCS/main.c,v 1.2 90/01/12 12:04:14 douglis Exp $ SPRITE (Berkeley)";
  475. d66 1
  476. d170 3
  477. d366 24
  478. @
  479.